# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import time
import sys
import smtplib

from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email import Encoders
from email.Utils import COMMASPACE, formatdate
from Peach.publisher import Publisher
from Peach.Engine.common import PeachException


class SMTPPublisher(Publisher):
    def __init__(self, host="localhost",
                 port=smtplib.SMTP_PORT,
                 debugLevel=0,
                 mailFrom="localhost@localhost",
                 mailTo="localhost@localhost",
                 username="",
                 password=""):
        Publisher.__init__(self)
        self.host = host
        try:
            self.port = int(port)
        except:
            raise PeachException("The SMTP publisher parameter for port is not a valid number.")
        self.debugLevel = int(debugLevel)
        self.mailFrom = mailFrom
        self.mailTo = mailTo
        self.username = username
        self.password = password
        self.loadBalance = 0
        self._connected = None

    def start(self):
        if self._connected:
            return

        print("[*] Connecting to %s:%d ..." % (self.host, self.port))
        try:
            self.smtp = smtplib.SMTP(self.host, self.port)
        except:
            raise PeachException("Peer %s:%d is down or connection settings are wrong." % (self.host, self.port))
        self._connected = True
        self.smtp.set_debuglevel(self.debugLevel)

    def connect(self):
        pass

    def send(self, data):
        if not self.loadBalance % 500 and self.loadBalance != 0:
            print("[*] Pause ...")
            time.sleep(10)
        for i in range(3):
            try:
                self.smtp.sendmail(self.mailFrom, self.mailTo, data)
                exception = None
                break
            except:
                exception = sys.exc_info()
            time.sleep(5)
        if exception:
            reason = ""
            try:
                reason = str(exception[1])
            except:
                reason = "unknown reason."
            message = "SMTP send mail to %s:%d failed: %s" % (self.host, self.port, reason)
            if message.find("5.4.0") > -1:
                print(message)
            else:
                self.smtp.close()
                raise PeachException(message)
        self.loadBalance += 1

    def close(self):
        pass

    def stop(self):
        pass


class EmailAttachment(Publisher):
    """
    Send fuzzed data as email attachment.
    """

    def __init__(self, server, fileName, msgTo, msgFrom="peach@peach.org",
                 msgSubject="Fuzzing Test",
                 msgText="Message generated by Peach Fuzzing Platform.\n\nhttp://peachfuzzer.com\n\n - Peach\n"):
        Publisher.__init__(self)
        self.server = server
        self.fileName = fileName
        self.msgFrom = msgFrom
        self.msgTo = msgTo
        self.msgSubject = msgSubject
        self.msgText = msgText

    def send(self, data):
        """
        Publish some data

        @type	data: string
        @param	data: Data to publish
        """
        # Build Message Body
        msg = MIMEMultipart()
        msg['From'] = self.msgFrom
        msg['To'] = self.msgTo
        msg['Date'] = formatdate(localtime=True)
        msg['Subject'] = self.msgSubject
        msg.attach(MIMEText(self.msgText))
        # Attach file
        part = MIMEBase('application', 'pdf')
        part.set_payload(data)
        Encoders.encode_base64(part)
        part.add_header('Content-Disposition', 'attachment; filename="%s"' % self.fileName)
        msg.attach(part)
        # Send email
        smtp = smtplib.SMTP(self.server)
        smtp.sendmail(self.msgFrom, self.msgTo, msg.as_string())
        smtp.close()

    def connect(self):
        """
        Called to connect or open a connection/file.
        """
        pass

    def close(self):
        """
        Close current stream/connection.
        """
        pass


class _OleStorage(object):
    """
    This class wraps OLE Storage APIs
    """
    pass
